from hashlib import md5
from os . path import dirname
from normalizer import run as normalizer_run
from normalizer . exception import exception as normalizer_exception
from reader import reader
from reader import exception as reader_exception
from utils import merge

def reify ( data , open_func , trace , options , os_mod ) :
    for raw_name , contents in sorted ( data . items ( ) ) :
        name = options . file_prefix ( ) + raw_name
        dir = dirname ( name )
        try :
            os_mod . makedirs ( dir )
            trace . dir_created ( dir )
        except :
            pass
        try :
            old_md5 = md5 ( open_func ( name , 'r' ) . read ( ) ) . hexdigest ( )
        except :
            old_md5 = None
        new_md5 = md5 ( contents ) . hexdigest ( )
        if new_md5 != old_md5 :
            try :
                open_func ( name , 'w' ) . write ( contents )
                if old_md5 is None :
                    trace . created ( name )
                else :
                    trace . overwritten ( name )
            except Exception as e :
                trace . write_error ( name , str ( e ) )

def generate ( input ) :
    res = { }
    res . update ( _generate_common_h ( ) )
    res . update ( _generate_common_hpp ( ) )
    res . update ( _generate_common_injections_h ( ) )
    res . update ( _generate_common_injections_cpp ( ) )
    res . update ( _generate_loadable_h ( ) )
    res . update ( _generate_loadable_hpp ( ) )
    res . update ( _generate_loadable_injections_h ( ) )
    res . update ( _generate_loadable_injections_cpp ( ) )
    return res

def _generate_common_h ( ) :
    return { 'autogenerated/common/shy_common.h' :
        'class shy_common\n'
        '{\n'
        'public :\n'
        '    static void init ( ) ;\n'
        '    static void done ( ) ;\n'
        '    static void next_frame ( ) ;\n'
        '} ;\n' }

def _generate_common_hpp ( ) :
    return { 'autogenerated/common/shy_common.hpp' :
        'void shy_common :: init ( )\n'
        '{\n'
        '}\n'
        '\n'
        'void shy_common :: done ( )\n'
        '{\n'
        '}\n'
        '\n'
        'void shy_common :: next_frame ( )\n'
        '{\n'
        '}\n' }

def _generate_common_injections_h ( ) :
    return { 'autogenerated/common/shy_common_injections.h' :
        '#ifndef _shy_common_injections_included\n'
        '#define _shy_common_injections_included\n'
        '\n'
        '#include "autogenerated/common/shy_common.h"\n'
        'typedef shy_common so_called_common ;\n'
        '\n'
        '#endif\n' }

def _generate_common_injections_cpp ( ) :
    return { 'autogenerated/common/shy_common_injections.cpp' :
        '#include "autogenerated/common/shy_common_injections.h"\n'
        '#include "autogenerated/common/shy_common.hpp"\n' }

def _generate_loadable_h ( ) :
    return { 'autogenerated/loadable/shy_loadable.h' :
        'class shy_loadable\n'
        '{\n'
        'public :\n'
        '    static void load ( ) ;\n'
        '} ;\n' }

def _generate_loadable_hpp ( ) :
    return { 'autogenerated/loadable/shy_loadable.hpp' :
        'void shy_loadable :: load ( )\n'
        '{\n'
        '}\n' }

def _generate_loadable_injections_h ( ) :
    return { 'autogenerated/loadable/shy_loadable_injections.h' :
        '#ifndef _shy_loadable_injections_included\n'
        '#define _shy_loadable_injections_included\n'
        '\n'
        '#include "autogenerated/loadable/shy_loadable.h"\n'
        'typedef shy_loadable so_called_loadable ;\n'
        '\n'
        '#endif\n' }

def _generate_loadable_injections_cpp ( ) :
    return { 'autogenerated/loadable/shy_loadable_injections.cpp' :
        '#include "autogenerated/loadable/shy_loadable_injections.h"\n'
        '#include "autogenerated/loadable/shy_loadable.hpp"\n' }

if __name__ == '__main__' :
    from sys import argv
    from sys import stdin
    import os
    from pprint import pprint
    from fractions import Fraction

    class trace :
        def write_error ( self , name , error ) :
            print 'Cannot write file "' + name + '": %s' % error
        def created ( self , name ) :
            print 'File "' + name + '" has been created.'
        def overwritten ( self , name ) :
            print 'File "' + name + '" has been overwritten.'
        def dir_created ( self , name ) :
            print 'Path "' + name + '" has been created.'

    class options :
        def file_prefix ( self ) :
            return argv [ 1 ]
        
    try :
        platform = \
            { 'platform_consts' :
                { 'platform_consts_seconds_per_frame' : Fraction ( 1 , 60 )
                , 'platform_math_consts_fract_2pi' : Fraction ( 6283184 , 1000000 )
                , 'true' : 1
                , 'false' : 0
                }
            , 'platform_types' :
                { 'platform_math_num_whole' : [ ]
                , 'platform_math_num_fract' : [ ]
                , 'platform_matrix_data' : [ ]
                , 'platform_render_index_buffer_id' : [ ]
                , 'platform_render_texture_id' : [ ]
                , 'platform_render_vertex_buffer_id' : [ ]
                , 'platform_vector_data' : [ ]
                }
            , 'platform_procs' :
                { 'platform_conditions_fract_greater_than_fract' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_conditions_fract_less_than_fract' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_conditions_whole_greater_or_equal_to_whole' : 
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_whole_greater_than_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_whole_greater_than_zero' : 
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_whole_is_false' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_whole_is_true' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_whole_less_or_equal_to_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_whole_less_than_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_whole_less_than_zero' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_wholes_are_equal' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_conditions_wholes_are_not_equal' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_add_fracts' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_add_wholes' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_add_to_fract' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_add_to_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_cos' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_dec_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_div_fract_by' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_div_whole_by' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_div_wholes' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_inc_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_make_fract_from_whole' : 
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_mul_fracts' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_mul_whole_by' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_mul_wholes' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_neg_fract' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_neg_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_sin' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_sub_fracts' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_sub_from_fract' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_math_sub_from_whole' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_math_sub_wholes' :
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } 
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_matrix_identity' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] } ] }
                , 'platform_matrix_inverse_rotation_translation' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] } ] }
                , 'platform_matrix_set_fract_axis_x' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_matrix_set_fract_axis_y' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_matrix_set_fract_axis_z' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_matrix_set_fract_origin' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } 
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_matrix_set_vector_axis_x' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_vector_data' : [ ] } ] }
                , 'platform_matrix_set_vector_axis_y' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_vector_data' : [ ] } ] }
                , 'platform_matrix_set_vector_axis_z' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_vector_data' : [ ] } ] }
                , 'platform_matrix_set_vector_origin' :
                    { 'args' : [ { 'platform_matrix_data' : [ ] }
                               , { 'platform_vector_data' : [ ] } ] }
                , 'platform_render_blend_disable' : { 'args' : [ ] }
                , 'platform_render_blend_src_alpha_dst_one_minus_alpha' : { 'args' : [ ] }
                , 'platform_render_clear_screen' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] }
                               , { 'platform_math_num_fract' : [ ] }
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_render_create_index_buffer' :
                    { 'args' : [ { 'platform_render_index_buffer_id' : [ ] }
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_render_create_texture_id' :
                    { 'args' : [ { 'platform_render_texture_id' : [ ] }
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_render_create_vertex_buffer' : 
                    { 'args' : [ { 'platform_render_vertex_buffer_id' : [ ] }
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_render_delete_index_buffer' :
                    { 'args' : [ { 'platform_render_index_buffer_id' : [ ] } ] }
                , 'platform_render_delete_texture_id' :
                    { 'args' : [ { 'platform_render_texture_id' : [ ] } ] }
                , 'platform_render_delete_vertex_buffer' :
                    { 'args' : [ { 'platform_render_vertex_buffer_id' : [ ] } ] }
                , 'platform_render_disable_depth_test' : { 'args' : [ ] }
                , 'platform_render_disable_texturing' : { 'args' : [ ] }
                , 'platform_render_draw_triangle_fan' :
                    { 'args' : [ { 'platform_render_vertex_buffer_id' : [ ] }
                               , { 'platform_render_index_buffer_id' : [ ] }
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_render_draw_triangle_strip' :
                    { 'args' : [ { 'platform_render_vertex_buffer_id' : [ ] }
                               , { 'platform_render_index_buffer_id' : [ ] }
                               , { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_render_enable_depth_test' : { 'args' : [ ] }
                , 'platform_render_enable_face_culling' : { 'args' : [ ] }
                , 'platform_render_enable_texturing' : { 'args' : [ ] }
                , 'platform_render_fog_disable' : { 'args' : [ ] }
                , 'platform_render_fog_linear' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] }
                               , { 'platform_math_num_fract' : [ ] }
                               , { 'platform_math_num_fract' : [ ] }
                               , { 'platform_math_num_fract' : [ ] }
                               , { 'platform_math_num_fract' : [ ] }
                               , { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_render_get_aspect_height' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_render_get_aspect_width' :
                    { 'args' : [ { 'platform_math_num_fract' : [ ] } ] }
                , 'platform_render_get_frame_loss' : 
                    { 'args' : [ { 'platform_math_num_whole' : [ ] } ] }
                , 'platform_render_load_texture_subdata' : { 'args' : [ { } ] * 6 }
                , 'platform_render_map_index_buffer' : { 'args' : [ { } ] * 2 }
                , 'platform_render_map_vertex_buffer' : { 'args' : [ { } ] * 2 }
                , 'platform_render_mapped_index_buffer_element' : { 'args' : [ { } ] * 3 }
                , 'platform_render_mapped_vertex_buffer_element' : { 'args' : [ { } ] * 3 }
                , 'platform_render_matrix_identity' : { 'args' : [ ] }
                , 'platform_render_matrix_load' : { 'args' : [ { } ] * 1 }
                , 'platform_render_matrix_mult' : { 'args' : [ { } ] * 1 }
                , 'platform_render_matrix_pop' : { 'args' : [ ] }
                , 'platform_render_matrix_push' : { 'args' : [ ] }
                , 'platform_render_projection_frustum' : { 'args' : [ { } ] * 6 }
                , 'platform_render_projection_ortho' : { 'args' : [ { } ] * 6 }
                , 'platform_render_set_index_value' : { 'args' : [ { } ] * 2 }
                , 'platform_render_set_texel_color' : { 'args' : [ { } ] * 5 }
                , 'platform_render_set_vertex_color' : { 'args' : [ { } ] * 5 }
                , 'platform_render_set_vertex_position' : { 'args' : [ { } ] * 4 }
                , 'platform_render_set_vertex_tex_coord' : { 'args' : [ { } ] * 3 }
                , 'platform_render_texture_loader_create_resource_id' : { 'args' : [ { } ] * 2 }
                , 'platform_render_texture_loader_load_resource' : { 'args' : [ { } ] * 3 }
                , 'platform_render_texture_loader_ready' : { 'args' : [ { } ] * 1 }
                , 'platform_render_texture_mode_modulate' : { 'args' : [ ] }
                , 'platform_render_unmap_index_buffer' : { 'args' : [ { } ] * 1 }
                , 'platform_render_unmap_vertex_buffer' : { 'args' : [ { } ] * 1 }
                , 'platform_render_use_texture' : { 'args' : [ { } ] * 1 }
                , 'platform_static_array_element_ptr' : { 'args' : [ { } ] * 3 }
                , 'platform_vector_add' : { 'args' : [ { } ] * 3 }
                , 'platform_vector_cross_product' : { 'args' : [ { } ] * 3 }
                , 'platform_vector_mul' : { 'args' : [ { } ] * 3 }
                , 'platform_vector_normalize' : { 'args' : [ { } ] * 2 }
                , 'platform_vector_sub' : { 'args' : [ { } ] * 3 }
                , 'platform_trace_trace_begin' : { 'args' : [ { } ] * 1 }
                , 'platform_trace_trace_end' : { 'args' : [ ] }
                , 'platform_trace_trace_num_whole' : { 'args' : [ { } ] * 1 }
                , 'platform_trace_trace_num_whole_error' : { 'args' : [ { } ] * 1 }
                , 'platform_trace_trace_string' : { 'args' : [ { } ] * 1 }
                , 'platform_trace_trace_string_error' : { 'args' : [ { } ] * 1 }
                , 'platform_vector_mul_by' : { 'args' : [ { } ] * 2 }
                , 'platform_vector_xyz' : { 'args' : [ { } ] * 4 }
            } }
        pprint ( normalizer_run ( merge ( platform , reader ( ) . run ( stdin ) ) ) )
    except reader_exception as e :
        pprint ( e . get_src ( ) )
        print 'reader exception:' , str ( e )
    except normalizer_exception as e :
        pprint ( e . get_src ( ) )
        print 'normalizer exception:' , str ( e )
        print 'at'
        pprint ( e . get_path ( ) )
    reify ( generate ( [ ] ) , open , trace ( ) , options ( ) , os )
